<?php
// +----------------------------------------------------------------------
// | 服务
// +----------------------------------------------------------------------
declare(strict_types=1);

namespace app\service;

use app\model\AccessSmsModel;
use DateTimeImmutable;
use think\exception\ValidateException;

/**
 * 短信发送与认证
 *
 * Class SmsAuthService
 * @package app\service
 */
class SmsAuthService
{

    /**
     * 获取过期时间
     * 
     * @return string
     */
    private static function getExpiresTime(): string
    {
        $now = new DateTimeImmutable();
        $day = $now->modify('+' . env('sms.deadline_minute') . ' minute');
        return $day->format('Y-m-d H:i:s');
    }

    /**
     * 获取发送间隔时间
     * 
     * @param string $time 时间
     * @return string
     */
    private static function getIntervalTime(string $time): string
    {
        $now = new DateTimeImmutable($time);
        $day = $now->modify('+' . env('sms.interval_second') . ' second');
        return $day->format('Y-m-d H:i:s');
    }

    /**
     * 获取随机验证码（6位）
     * 
     * @return string
     */
    private static function geneRandomCode(): string
    {
        return (string)rand(100000, 999999);
    }

    /**
     * 生成短信（失败抛出错误）
     * 
     * @param string $phone 手机号
     * 
     * @return string
     */
    public static function genePhoneSms(string $phone): string
    {
        $code = self::geneRandomCode();
        $lastSms = AccessSmsModel::where('phone_number', $phone)->order('id', 'desc')->find();
        if ($lastSms) {
            if (date('Y-m-d H:i:s') < self::getIntervalTime($lastSms->send_time)) {
                throw new ValidateException('短信发送过于频繁，请稍后再试');
            }
        }
        // 生成新的短信
        // 按照正常流程，这里需要推送发送短信队列并执行，完成后修改send_time
        // 这里仅作模拟
        AccessSmsModel::create([
            'phone_number' => $phone,
            'code'         => $code,
            'send_time'    => date('Y-m-d H:i:s'),
            'expire_time'  => self::getExpiresTime(),
        ]);
        return $code;
    }

    /**
     * 验证短信验证码（失败抛出错误）
     * 
     * @param string $phone 手机号
     * @param string $code 验证码
     * 
     * @return bool
     */
    public static function verifyPhoneSms(string $phone, string $code): bool
    {
        $sms = AccessSmsModel::where('phone_number', $phone)
            ->where('code', $code)
            ->where('is_used', false)
            ->find();

        if (!$sms || $sms->expire_time < date('Y-m-d H:i:s')) {
            throw new ValidateException('认证失败：无效的验证码');
        }
        // 验证成功后标记为已使用
        $sms->setAttr('is_used', true);
        $sms->save();
        return true;
    }
}
